import { program } from 'commander';
import dayjs from 'dayjs';
import colors from 'colors/safe';

import * as Enums from '../utils/Enums';
import PathHelper from '../utils/PathHelper';
import Printer from '../utils/Printer';
import ExecuteHelper from '../utils/ExecuteHelper';
import { InternalApps, InternalServices, ExternalApps } from '../config/Modules';
import { commandFetch } from './fetch';
import { build } from './build';

interface FetchCommandOptions {
  env: string,
  'nginx-port'?: string,
}

const dockerBuild = async (options: FetchCommandOptions) => {
  if (!options.env) {
    Printer.warn('请指定构建的目标环境');
    return;
  }
  const buildStartedAt = dayjs();

  Printer.log(colors.bgGreen('从 GitLab 拉取外部子应用代码...'));
  commandFetch({ modules: 'all' });
  Printer.log(colors.bgGreen('更新 cli ...'));
  ExecuteHelper.run('yarn && yarn build', { cwd: PathHelper.getPathAtRoot() });

  Printer.log(colors.bgGreen('构建各服务和应用...'));
  const buildingPromise: Array<Promise<void>> = [];
  Object.values(InternalServices).forEach((internalService) => {
    buildingPromise.push(build({ type: Enums.ModuleType.Service, module: internalService, env: options.env }));
  });
  Object.values(InternalApps).forEach((internalApp) => {
    buildingPromise.push(build({ type: Enums.ModuleType.App, module: internalApp, env: options.env }));
  });
  Object.values(ExternalApps).forEach((externalApp) => {
    buildingPromise.push(build({ type: Enums.ModuleType.App, module: externalApp, env: options.env }));
  });
  await Promise.all(buildingPromise);

  Printer.log(colors.bgGreen('构建 docker 镜像...'));
  const nginxListenPort = options['nginx-port'] || 8100;
  ExecuteHelper.run(
    `NGINX_LISTEN_PORT=${nginxListenPort} docker compose build`,
    { cwd: PathHelper.getPathRelativeToRoot('../') },
  );

  Printer.log(colors.bgGreen('导出 docker 镜像...'));
  ExecuteHelper.run(
    'rm -rf ./docker.dist'
    + ' && mkdir -p ./docker.dist'
    + ' && cp ./docker-compose.yml ./docker.dist/docker-compose.yml',
    { cwd: PathHelper.getPathRelativeToRoot('../') },
  );
  const now = dayjs().format('YYYY-MM-DDTHH:mm');
  const dockerSavePromises = [
    ExecuteHelper.asyncRun(
      `docker save cns-frontend/proxy | gzip > ./docker.dist/cns-frontend-proxy.${now}.tar.gz`,
      { cwd: PathHelper.getPathRelativeToRoot('../') },
    ),
    ExecuteHelper.asyncRun(
      `docker save cns-frontend/nginx | gzip > ./docker.dist/cns-frontend-nginx.${options.env}.${now}.tar.gz`,
      { cwd: PathHelper.getPathRelativeToRoot('../') },
    ),
  ];
  await Promise.all(dockerSavePromises);
  const buildDuration = Printer.getDurationAsSecond(buildStartedAt, dayjs());
  Printer.log(`${colors.bgGreen('构建与导出完毕')} --> ${PathHelper.getPathRelativeToRoot('../docker.dist')} > ${buildDuration}s`);
};

export default program
  .command('docker-build')
  .description('使用本地代码和 docker 配置构建并导出镜像')
  .option('-e, --env [env]', '指定构建的目标环境')
  .option('--nginx-port [nginx-port]', '指定 nginx 服务监听的端口号，默认为 8100')
  .action(dockerBuild);
